<!DOCTYPE html>
          <head>
        <meta charset="utf-8">
            
            <title>
                「Android-Bluetooth」0x01操作 | ttdevs
            </title>
            <meta content="width=device-width, initial-scale=1" name="viewport">
            <meta name="theme-color" content="#4184f3">
            
            
            <link href="/favicon.ico" rel="icon"/>
            

            <link rel="stylesheet" href="/css/highlight.light.css">
            <link rel="stylesheet" href="/css/prism-customize.css">
            <link rel="stylesheet" href="/css/nav-icon.css">
            <link rel="stylesheet" href="/css/waves.min.css">
            <link rel="stylesheet" href="/css/jquery.tocify.css">
            <link rel="stylesheet" href="/css/main.css">
            <link rel="stylesheet" href="/css/nav-indicator.css">
            
  

  
  <!-- 谷歌统计 -->
  <script>
    (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
    (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
    m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
    })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

    ga('create', 'UA-97465173-1', 'auto');
    ga('send', 'pageview');

  </script>
  
            </meta>
        </meta>
    </head>

    <body>
        <header>
            <!-- cover image or sth. -->
        </header>
        <div id="main" class="m-scene">
            
<div class="nav-wrapper">

    <div class="container">
        <nav>
            <div class="logo wave">
                <a href="/" id="logo">
                    ttdevs
                </a>
            </div>
            <div class="nav-toggle-icon" >
                <div class="material-hamburger">
                    <span>
                    </span>
                    <span>
                    </span>
                    <span>
                    </span>
                </div>
            </div>
            <div class="menu-wrapper">
                <div class="nav-indicator">
                </div>
                <ul class="menus">
                    
                     
                        <li>
                            <a class="wave " href="/">
                                首页
                            </a>
                        </li>
                     
                        <li>
                            <a class="wave " href="/archives">
                                归档
                            </a>
                        </li>
                     
                        <li>
                            <a class="wave " href="/about">
                                关于
                            </a>
                        </li>
                     
                    
                   
                </ul>
            </div>
        </nav>
    </div>
</div>
            <div class="container content">
                <div class="scene_element scene_element--fadein">
                    <div class="row">
    <div class="main">
        <article>
          
          <header class="post-header with-cover" style="background-image:url('/1970/01/01/[Android-Bluetooth]0x01操作/cover.jpg')" >
          
          </header>
          <h1 class="post-title">「Android-Bluetooth」0x01操作</h1>

          <section class="post-info">
            <span class="post-date">1970/01/01</span>
            
            <span class="post-category">
                <a class="article-category-link" href="/categories/技术/">技术</a>
            </span>
            
            
            <span class="post-tags">
              <ul class="post-tag-list"><li class="post-tag-list-item"><a class="post-tag-list-link" href="/tags/Android/">Android</a></li><li class="post-tag-list-item"><a class="post-tag-list-link" href="/tags/Bluetooth/">Bluetooth</a></li></ul>
            </span>
            
          </section>

          <section class="post-content">
            <h2 id="0x00-蓝牙（Bluetooth）"><a href="/1970/01/01/[Android-Bluetooth]0x01操作/#0x00-蓝牙（Bluetooth）" class="headerlink" title="0x00 蓝牙（Bluetooth）"></a>0x00 蓝牙（Bluetooth）</h2><p>这个小硬件已经是Android机器的标配了，由于平时不怎么用，因此到现在都没有去研究过。现在有一个简单的小需求：通过蓝牙连接一个串口设备读取其上面的数据，即从已配对的设备列表中选择我们的串口蓝牙设备（从），连接，然后读取数据。遂写此文。</p>
<h2 id="0x01-简单使用"><a href="/1970/01/01/[Android-Bluetooth]0x01操作/#0x01-简单使用" class="headerlink" title="0x01 简单使用"></a>0x01 简单使用</h2><p>蓝牙设备的详细使用，可以参考<a href="https://developer.android.google.cn/guide/topics/connectivity/bluetooth.html" target="_blank" rel="external">Android关于蓝牙的官方文档</a>。如果你和我一样，之前没有研究过蓝牙，估计看看完后也会有一堆问题存在：什么主设备、从设备、UUID是干嘛的，如何免密钥配对等等。不着急，我们慢慢来。</p>
<p>上面已经说到，我们的设备已经提前配对完成（怎么配对：网络设置中中找到蓝牙，然后搜索，找到你的设备，然后配对。这个时候可能会提示输入密码，默认密码比0000，1234等）。我们只需要连接即可。下面简述操作步骤：</p>
<ol>
<li><p>添加蓝牙权限</p>
 <figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">uses-permission</span> <span class="attr">android:name</span>=<span class="string">"android.permission.BLUETOOTH"</span> /&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">uses-permission</span> <span class="attr">android:name</span>=<span class="string">"android.permission.BLUETOOTH_ADMIN"</span> /&gt;</span></div></pre></td></tr></table></figure>
</li>
</ol>
<ol>
<li><p>判断是否支持蓝牙</p>
 <figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">initBluetooth</span><span class="params">()</span> </span>&#123;</div><div class="line">    mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();</div><div class="line">    <span class="keyword">if</span> (<span class="keyword">null</span> == mBluetoothAdapter) &#123;</div><div class="line">        tvContent.setText(<span class="string">"BluetoothAdapter is null"</span>);</div><div class="line">        <span class="keyword">return</span>;</div><div class="line">    &#125;</div><div class="line">    <span class="keyword">if</span> (!mBluetoothAdapter.isEnabled()) &#123;</div><div class="line">        tvContent.setText(<span class="string">"BluetoothAdapter is disable, please open it"</span>);</div><div class="line"></div><div class="line">        Intent intent = <span class="keyword">new</span> Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);</div><div class="line">        startActivityForResult(intent, REQUEST_ENABLE_BT);</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    tvContent.setText(<span class="string">"Bluetooth init success"</span>);</div><div class="line">&#125;</div></pre></td></tr></table></figure>
</li>
</ol>
<pre><code>首先是判断是否有蓝牙适配器，如果没有，`BluetoothAdapter.getDefaultAdapter()` 返回 `null`。然后判断蓝牙设备是否启用 `mBluetoothAdapter.isEnabled()` ，如果未启用，则发送一个 `Intent` 来让用户启用蓝牙，这个 `Intent` 是系统的，我们在 `onActivityResult` 中处理用户操作结果，如果用户顺利开启蓝牙，则会返回 `RESULT_OK`。
</code></pre><ol>
<li><p>获取设备列表</p>
 <figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line">Set&lt;BluetoothDevice&gt; pairedDevices = mBluetoothAdapter.getBondedDevices();</div><div class="line"><span class="keyword">if</span> (<span class="keyword">null</span> != pairedDevices &amp;&amp; pairedDevices.size() &gt; <span class="number">0</span>) &#123;</div><div class="line">  <span class="keyword">for</span> (BluetoothDevice device : pairedDevices) &#123;</div><div class="line">      ......</div><div class="line">      String msg = String.format(<span class="string">"%s %s\n"</span>, device.getName(), device.getAddress());</div><div class="line">      ......</div><div class="line">  &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
</li>
</ol>
<pre><code>这个时候我们可以拿到 `BluetoothDevice` ，这个对象中保存了已配对蓝牙设备的信息，比如名称，MAC地址，状态，UUID等信息（但这些信息不一定都都），我们需要保存下来，在接下来连接的时候会使用。
</code></pre><ol>
<li><p>连接设备</p>
<p> 有了 <code>BluetoothDevice</code> 信息，我们就可以连接这个已经配对的蓝牙设备了。</p>
 <figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div></pre></td><td class="code"><pre><div class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> UUID DEFAULT_UUID = UUID.fromString(<span class="string">"00001101-0000-1000-8000-00805f9b34fb"</span>);</div><div class="line"></div><div class="line"> <span class="keyword">try</span> &#123;</div><div class="line">    <span class="keyword">if</span>(<span class="keyword">null</span> == mSocket)&#123;</div><div class="line">        mSocket = mDevice.createRfcommSocketToServiceRecord(DEFAULT_UUID);</div><div class="line">    &#125;</div><div class="line">    mSocket.connect(); <span class="comment">// 阻塞的</span></div><div class="line"></div><div class="line">    mIn = mSocket.getInputStream();</div><div class="line">&#125; <span class="keyword">catch</span> (IOException e) &#123;</div><div class="line">    e.printStackTrace();</div><div class="line">    <span class="keyword">return</span> <span class="keyword">false</span>;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
</li>
</ol>
<pre><code>连接成功后，我们会得到一个 `BluetoothSocket` 对象，然后调用其阻塞的 `connect()` 方法，等待两台设备连接成功（所以这个时候必须在另外一个线程中进行）。当两台设备连接成功之后会继续向下执行。
</code></pre><ol>
<li><p>读取数据</p>
<p> 连接成功之后，我们可以通过 <code>mSocket.getInputStream()</code> 获得一个输入流，结下来的操作就是流的操作了，这个和普通 <code>socket</code> 中输入输出流的操作一样了。</p>
 <figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line"> <span class="keyword">try</span> &#123;</div><div class="line">    mBytes = mIn.read(readBuffer);</div><div class="line">    System.arraycopy(readBuffer, <span class="number">0</span>, tempBuffer, mCount, mBytes);</div><div class="line">    mCount += mBytes;</div><div class="line">    <span class="keyword">if</span> (mCount &gt;= SIZE) &#123;</div><div class="line">        parseData(tempBuffer);</div><div class="line">        mCount = <span class="number">0</span>;</div><div class="line">    &#125;</div><div class="line">&#125; <span class="keyword">catch</span> (IOException e) &#123;</div><div class="line">    e.printStackTrace();</div><div class="line">&#125;</div></pre></td></tr></table></figure>
</li>
</ol>
<h2 id="0x02-总结"><a href="/1970/01/01/[Android-Bluetooth]0x01操作/#0x02-总结" class="headerlink" title="0x02 总结"></a>0x02 总结</h2><p>Android蓝牙（主从）的操作：</p>
<ul>
<li>检查是否支持，是否启用（包括是否可见等）</li>
<li>扫描设备</li>
<li>配对</li>
<li>连接</li>
<li>数据交换</li>
<li>等等</li>
</ul>
<p>这里只讲了检查部分操作，涉及的扫描与配对可能是更复杂一些的，在接下来讲述。</p>
<p>最后，项目代码可参考这里<a href="https://github.com/ttdevs/android/tree/master/apps/air" target="_blank" rel="external">github/ttdevs/air</a>。</p>
<h2 id="0x03-Java线程的封装"><a href="/1970/01/01/[Android-Bluetooth]0x01操作/#0x03-Java线程的封装" class="headerlink" title="0x03 Java线程的封装"></a>0x03 Java线程的封装</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line"> * Created by ttdevs</div><div class="line"> * 2017-01-22 (android)</div><div class="line"> * https://github.com/ttdevs</div><div class="line"> */</div><div class="line"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">BaseWorkerThread</span> <span class="keyword">extends</span> <span class="title">Thread</span> </span>&#123;</div><div class="line"></div><div class="line">    <span class="keyword">private</span> <span class="keyword">boolean</span> isRunning = <span class="keyword">true</span>;</div><div class="line"></div><div class="line">    <span class="meta">@Override</span></div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</div><div class="line">        <span class="keyword">super</span>.run();</div><div class="line">        isRunning = workerBefore();</div><div class="line"></div><div class="line">        <span class="keyword">while</span> (isRunning) &#123;</div><div class="line">            workerCycle();</div><div class="line">        &#125;</div><div class="line"></div><div class="line">        workerAfter();</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="comment">/**</span></div><div class="line">     * 提前执行 true: 继续 false: 结束</div><div class="line">     *</div><div class="line">     * <span class="doctag">@return</span></div><div class="line">     */</div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">workerBefore</span><span class="params">()</span> </span>&#123;</div><div class="line">        <span class="keyword">return</span> <span class="keyword">true</span>;</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="comment">/**</span></div><div class="line">     * 工作方法，被循环调用</div><div class="line">     *</div><div class="line">     * <span class="doctag">@return</span> true: 继续 false: 结束</div><div class="line">     */</div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">void</span> <span class="title">workerCycle</span><span class="params">()</span></span>;</div><div class="line"></div><div class="line"></div><div class="line">    <span class="comment">/**</span></div><div class="line">     * 结束执行</div><div class="line">     */</div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">workerAfter</span><span class="params">()</span> </span>&#123;</div><div class="line"></div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="comment">/**</span></div><div class="line">     * 开始线程</div><div class="line">     */</div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">startThread</span><span class="params">()</span> </span>&#123;</div><div class="line">        isRunning = <span class="keyword">true</span>;</div><div class="line">        <span class="keyword">try</span> &#123;</div><div class="line">            start();</div><div class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</div><div class="line">            e.printStackTrace();</div><div class="line">            isRunning = <span class="keyword">false</span>;</div><div class="line">        &#125;</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="comment">/**</span></div><div class="line">     * 结束线程</div><div class="line">     */</div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">stopThread</span><span class="params">()</span> </span>&#123;</div><div class="line">        isRunning = <span class="keyword">false</span>;</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<h2 id="0x04-参考"><a href="/1970/01/01/[Android-Bluetooth]0x01操作/#0x04-参考" class="headerlink" title="0x04 参考"></a>0x04 参考</h2><ul>
<li><a href="https://developer.android.google.cn/guide/topics/connectivity/bluetooth.html" target="_blank" rel="external">https://developer.android.google.cn/guide/topics/connectivity/bluetooth.html</a></li>
</ul>
<p><img src="https://raw.githubusercontent.com/ttdevs/ttdevs.github.io/common/images/logo.png" alt="Create by ttdevs"></p>

          </section>
        </article>
        

       
        <div class="pager">
          
            <a class="post-prev pager-item" href="/1970/01/01/[玩转树莓派]0x06DS18B20温度检测/" >
              <strong class="article-nav-caption">上一篇</strong>
              <p class="post-nav-title">「玩转树莓派」0x06DS18B20温度检测</p>
            </a>
          
          
            <a class="post-next pager-item" href="/1970/01/01/[Android-SQLite]0x02从加载本地数据库开始/">
              <strong class="article-nav-caption">下一篇</strong>
              <p class="post-nav-title">「Android-SQLite」0x02从加载本地数据库开始</p>
            </a>
          
        </div>
        

         <!-- comments -->
        <div class="comment-section">
  
    


</div>

    </div>
    
    <aside>
        <div id="toc">
        </div>
    </aside>
    
</div>

                </div>
            </div>
        </div>
        <footer class="footer">
    <p>由<a href="http://hexo.io/" target="_blank">Hexo</a>强力驱动，搭载<a href="https://github.com/wayou/hexo-theme-gstyle">gstyle</a>主题</p>
    <p>
        &copy; 2017 ttdevs
    </p>
</footer>
<script src="/lib/jquery.js"></script>
<script src="/lib/waves.js"></script>
<script src="/lib/jquery-ui.js"></script>
<script src="/lib/jquery.tocify.js"></script>
<script src="/js/main.js"></script>

    </body>
</html>
